In [ ]:
import pandas as pd
import numpy as np
symbol = 'Security 1'
symbol2 = 'Security 2'

In [ ]:
price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.4], [0.4, 1.0]]), axis=0) + 100,
                          columns=['Security 1', 'Security 2'],
                          index=pd.date_range(start='01-01-2007', periods=150))

dates_actual = price_data.index.values
prices = price_data[symbol].values

In [ ]:
from bqplot import (DateScale, LinearScale, Axis, Lines, Scatter, Bars, Hist, Figure)
from bqplot.interacts import (FastIntervalSelector, IndexSelector, BrushIntervalSelector,
                              BrushSelector, MultiSelector, LassoSelector, PanZoom, HandDraw)
from traitlets import link

from IPython.display import display
from ipywidgets import Label, ToggleButtons, VBox

Line Chart Selectors

Fast Interval Selector


In [ ]:
## First we define a Figure
dt_x_fast = DateScale()
lin_y = LinearScale()

x_ax = Axis(label="Index", scale=dt_x_fast)
x_ay = Axis(label=(symbol + " Price"), scale=lin_y, orientation="vertical", tick_format="0.2f")
lc = Lines(x=dates_actual, y=prices, scales={'x': dt_x_fast, 'y': lin_y}, colors=['orange'])
lc_2 = Lines(x=dates_actual[50:], y=prices[50:] + 2, scales={'x': dt_x_fast, 'y': lin_y}, colors=['blue'])

In [ ]:
## Next we define the type of selector we would like
intsel_fast = FastIntervalSelector(scale=dt_x_fast, marks=[lc, lc_2])

In [ ]:
## Now, we define a function that will be called when the FastIntervalSelector is interacted with
def fast_interval_change_callback(change):
    db_fast.value = 'The selected period is ' + str(change['new'])

In [ ]:
## Now we connect the selectors to that function
intsel_fast.observe(fast_interval_change_callback, names=['selected'])

In [ ]:
## We use the Label widget to see the value of what we are selecting and modify it when an interaction is performed
## on the selector
db_fast = Label(color='Black', font_size='24px')
db_fast.value = str(intsel_fast.selected)
display(db_fast)

fig_fast_intsel = Figure(marks=[lc, lc_2], axes=[x_ax, x_ay], title="Fast Interval Selector Example",
                         interaction=intsel_fast) #This is where we assign the interaction to this particular Figure
display(fig_fast_intsel)

Index Selector


In [ ]:
db_index = Label(color='Black', font_size='24px', value='[]')

In [ ]:
## Now we try a selector made to select all the y-values associated with a single x-value
index_sel = IndexSelector(scale=dt_x_fast, marks=[lc, lc_2])

In [ ]:
## Now, we define a function that will be called when the selectors are interacted with
def index_change_callback(change):
    db_index.value = 'The selected date is ' + str(change['new'])

In [ ]:
index_sel.observe(index_change_callback, names=['selected'])

In [ ]:
fig_index_sel = Figure(marks=[lc, lc_2], axes=[x_ax, x_ay], title="Index Selector Example",
                       interaction=index_sel)
display(db_index)
display(fig_index_sel)

Returning indexes of selected values


In [ ]:
from datetime import datetime as py_dtime

dt_x_index = DateScale(min=np.datetime64(py_dtime(2006, 6, 1)))
lin_y2 = LinearScale()

lc2_index = Lines(x=dates_actual, y=prices,
            scales={'x': dt_x_index, 'y': lin_y2})

x_ax1 = Axis(label="Date", scale=dt_x_index)
x_ay2 = Axis(label=(symbol + " Price"), scale=lin_y2, orientation="vertical", tick_format="0.2f")

In [ ]:
intsel_date = FastIntervalSelector(scale=dt_x_index, marks=[lc2_index])

In [ ]:
db_date = Label(color='Black', font_size='24px')
db_date.value = str(intsel_date.selected)

In [ ]:
## Now, we define a function that will be called when the selectors are interacted with - a callback
def date_interval_change_callback(change):
    db_date.value = str(change['new'])

In [ ]:
## Notice here that we call the observe on the Mark lc2_index rather than on the selector intsel_date
lc2_index.observe(date_interval_change_callback, names=['selected'])

fig_date_mark = Figure(marks=[lc2_index], axes=[x_ax1, x_ay2],
                       title='Fast Interval Selector Selected Indices Example', interaction=intsel_date)

display(db_date)
display(fig_date_mark)

Brush Selector

We can do the same with any type of selector


In [ ]:
## Defining a new Figure
dt_x_brush = DateScale(min=np.datetime64(py_dtime(2006, 6, 1)))
lin_y2_brush = LinearScale()

lc3_brush = Lines(x=dates_actual, y=prices,
            scales={'x': dt_x_brush, 'y': lin_y2_brush})

x_ax_brush = Axis(label="Date", scale=dt_x_brush)
x_ay_brush = Axis(label=(symbol + " Price"), scale=lin_y2_brush, orientation="vertical", tick_format="0.2f")

In [ ]:
db_brush = Label(color='Black', font_size='24px', value='[]')

In [ ]:
brushsel_date = BrushIntervalSelector(scale=dt_x_brush, marks=[lc3_brush], color='FireBrick')

In [ ]:
## Now, we define a function that will be called when the selectors are interacted with - a callback
def date_brush_change_callback(change):
    db_brush.value = str(change['new'])

In [ ]:
lc3_brush.observe(date_brush_change_callback, names=['selected'])

In [ ]:
fig_brush_sel = Figure(marks=[lc3_brush], axes=[x_ax_brush, x_ay_brush],
                       title="Brush Selector Selected Indices Example", interaction=brushsel_date)

display(db_brush)
display(fig_brush_sel)

Scatter Chart Selectors

Brush Selector


In [ ]:
date_fmt = '%m-%d-%Y'

sec2_data = price_data[symbol2].values
dates = price_data.index.values

In [ ]:
sc_x = LinearScale()
sc_y = LinearScale()

scatt = Scatter(x=prices, y=sec2_data,
                scales={'x': sc_x, 'y': sc_y})

sc_xax = Axis(label=(symbol), scale=sc_x, tick_format="0.0f")
sc_yax = Axis(label=(symbol2), scale=sc_y, orientation="vertical", tick_format="0.0f")

In [ ]:
br_sel = BrushSelector(x_scale=sc_x, y_scale=sc_y, marks=[scatt], color='red')

db_scat_brush = Label(color='Black', font_size='24px', value='[]')

In [ ]:
## call back for the selector
def brush_callback(change):
    db_scat_brush.value = str(br_sel.selected)

In [ ]:
br_sel.observe(brush_callback, names=['brushing'])

In [ ]:
fig_scat_brush = Figure(marks=[scatt], axes=[sc_xax, sc_yax], title='Scatter Chart Brush Selector Example',
                        interaction=br_sel)

In [ ]:
display(db_scat_brush)
display(fig_scat_brush)

Brush Selector with Date Values


In [ ]:
sc_brush_dt_x = DateScale(date_format=date_fmt)
sc_brush_dt_y = LinearScale()

scatt2 = Scatter(x=dates_actual, y=sec2_data,
                scales={'x': sc_brush_dt_x, 'y': sc_brush_dt_y})

In [ ]:
br_sel_dt = BrushSelector(x_scale=sc_brush_dt_x, y_scale=sc_brush_dt_y, marks=[scatt2])

In [ ]:
db_brush_dt = Label(color='Black', font_size='24px')
db_brush_dt.value = str(br_sel_dt.selected)

In [ ]:
## call back for the selector
def brush_dt_callback(change):
    db_brush_dt.value = str(br_sel_dt.selected)

In [ ]:
br_sel_dt.observe(brush_callback, names=['brushing'])

In [ ]:
sc_xax = Axis(label=(symbol), scale=sc_brush_dt_x)
sc_yax = Axis(label=(symbol2), scale=sc_brush_dt_y, orientation="vertical", tick_format="0.0f")
fig_brush_dt = Figure(marks =[scatt2], axes=[sc_xax, sc_yax], title='Brush Selector with Dates Example',
                      interaction=br_sel_dt)

In [ ]:
display(db_brush_dt)
display(fig_brush_dt)

Histogram Selectors


In [ ]:
## call back for selectors
def interval_change_callback(name, value):
    db3.value = str(value)
    
## call back for the selector
def brush_callback(change):
    if(not br_intsel.brushing):
        db3.value = str(br_intsel.selected)

In [ ]:
returns = np.log(prices[1:]) - np.log(prices[:-1])
hist_x = LinearScale()
hist_y = LinearScale()
hist = Hist(sample=returns, scales={'sample': hist_x, 'count': hist_y})

br_intsel = BrushIntervalSelector(scale=hist_x, marks=[hist])
br_intsel.observe(brush_callback, names=['selected'])
br_intsel.observe(brush_callback, names=['brushing'])

db3 = Label(color='Black', font_size='24px')
db3.value = str(br_intsel.selected)
display(db3)

h_xax = Axis(scale=hist_x, label='Returns', grids='off', set_ticks=True, tick_format='0.2%')
h_yax = Axis(scale=hist_y, label='Freq', orientation='vertical', grids='off')

fig_hist = Figure(marks=[hist], axes=[h_xax, h_yax], title='Histogram Selection Example', interaction=br_intsel)
display(fig_hist)

Multi Selector


In [ ]:
def multi_sel_callback(change):
    if(not multi_sel.brushing):
        db4.value = str(multi_sel.selected)

In [ ]:
line_x = LinearScale()
line_y = LinearScale()
line = Lines(x=np.arange(100), y=np.random.randn(100), scales={'x': line_x, 'y': line_y})

multi_sel = MultiSelector(scale=line_x, marks=[line])
multi_sel.observe(multi_sel_callback, names=['selected'])
multi_sel.observe(multi_sel_callback, names=['brushing'])

db4 = Label(color='Black', font_size='24px')
db4.value = str(multi_sel.selected)
display(db4)

h_xax = Axis(scale=line_x, label='Returns', grids='off', set_ticks=True)
h_yax = Axis(scale=hist_y, label='Freq', orientation='vertical', grids='off')

fig_multi = Figure(marks=[line], axes=[h_xax, h_yax], title='Multi-Selector Example',
                   interaction=multi_sel)
display(fig_multi)

In [ ]:
# changing the names of the intervals.
multi_sel.names = ['int1', 'int2', 'int3']

Multi Selector with Date X


In [ ]:
def multi_sel_dt_callback(change):
    if(not multi_sel_dt.brushing):
        db_multi_dt.value = str(multi_sel_dt.selected)

In [ ]:
line_dt_x = DateScale(min=np.datetime64(py_dtime(2007, 1, 1)))
line_dt_y = LinearScale()
line_dt = Lines(x=dates_actual, y=sec2_data, scales={'x': line_dt_x, 'y': line_dt_y}, colors=['red'])

multi_sel_dt = MultiSelector(scale=line_dt_x)
multi_sel_dt.observe(multi_sel_dt_callback, names=['selected'])
multi_sel_dt.observe(multi_sel_dt_callback, names=['brushing'])

db_multi_dt = Label(color='Black', font_size='24px')
db_multi_dt.value = str(multi_sel_dt.selected)
display(db_multi_dt)

h_xax_dt = Axis(scale=line_dt_x, label='Returns', grids='off')
h_yax_dt = Axis(scale=line_dt_y, label='Freq', orientation='vertical', grids='off')

fig_multi_dt = Figure(marks=[line_dt], axes=[h_xax_dt, h_yax_dt], title='Multi-Selector with Date Example',
                      interaction=multi_sel_dt)
display(fig_multi_dt)

Lasso Selector


In [ ]:
lasso_sel = LassoSelector()

In [ ]:
xs, ys = LinearScale(), LinearScale()
data = np.arange(20)
line_lasso = Lines(x=data, y=data, scales={'x': xs, 'y': ys})
scatter_lasso = Scatter(x=data, y=data, scales={'x': xs, 'y': ys}, colors=['skyblue'])
bar_lasso = Bars(x=data, y=data/2., scales={'x': xs, 'y': ys})
xax_lasso, yax_lasso = Axis(scale=xs, label='X'), Axis(scale=ys, label='Y', orientation='vertical')
fig_lasso = Figure(marks=[scatter_lasso, line_lasso, bar_lasso], axes=[xax_lasso, yax_lasso],
                   title='Lasso Selector Example', interaction=lasso_sel)
lasso_sel.marks = [scatter_lasso, line_lasso]
display(fig_lasso)

In [ ]:
scatter_lasso.selected, line_lasso.selected

Pan Zoom


In [ ]:
xs_pz = DateScale(min=np.datetime64(py_dtime(2007, 1, 1)))
ys_pz = LinearScale()
line_pz = Lines(x=dates_actual, y=sec2_data, scales={'x': xs_pz, 'y': ys_pz}, colors=['red'])

panzoom = PanZoom(scales={'x': [xs_pz], 'y': [ys_pz]})
xax = Axis(scale=xs_pz, label='Date', grids='off')
yax = Axis(scale=ys_pz, label='Price', orientation='vertical', grids='off')

fig_pz = Figure(marks=[line_pz], axes=[xax, yax], interaction=panzoom)
display(fig_pz)

Hand Draw


In [ ]:
xs_hd = DateScale(min=np.datetime64(py_dtime(2007, 1, 1)))
ys_hd = LinearScale()
line_hd = Lines(x=dates_actual, y=sec2_data, scales={'x': xs_hd, 'y': ys_hd}, colors=['red'])

handdraw = HandDraw(lines=line_hd)
xax = Axis(scale=xs_hd, label='Date', grids='off')
yax = Axis(scale=ys_hd, label='Price', orientation='vertical', grids='off')

fig_hd = Figure(marks=[line_hd], axes=[xax, yax], interaction=handdraw)
display(fig_hd)

Unified Figure with All Interactions


In [ ]:
dt_x = DateScale(date_format=date_fmt, min=py_dtime(2007, 1, 1))
lc1_x = LinearScale()
lc2_y = LinearScale()

lc2 = Lines(x=np.linspace(0.0, 10.0, len(prices)), y=prices * 0.25,
            scales={'x': lc1_x, 'y': lc2_y}, 
            display_legend=True,
            labels=['Security 1'])

lc3 = Lines(x=dates_actual, y=sec2_data,
            scales={'x': dt_x, 'y': lc2_y},
            colors=['red'], 
            display_legend=True, 
            labels=['Security 2'])

lc4 = Lines(x=np.linspace(0.0, 10.0, len(prices)), y=sec2_data * 0.75,
            scales={'x': LinearScale(min=5, max=10), 'y': lc2_y},
            colors=['green'], display_legend=True, 
            labels=['Security 2 squared'])

x_ax1 = Axis(label='Date', scale=dt_x)
x_ax2 = Axis(label='Time', scale=lc1_x, side='top')
x_ay2 = Axis(label=(symbol + ' Price'), scale=lc2_y, orientation='vertical', tick_format='0.2f')


fig = Figure(marks=[lc2, lc3, lc4], axes=[x_ax1, x_ax2, x_ay2])

In [ ]:
## declaring the interactions
multi_sel = MultiSelector(scale=dt_x, marks=[lc2, lc3])
br_intsel = BrushIntervalSelector(scale=lc1_x, marks=[lc2, lc3])
index_sel = IndexSelector(scale=dt_x, marks=[lc2, lc3])
int_sel = FastIntervalSelector(scale=dt_x, marks=[lc3, lc2])

hd = HandDraw(lines=lc2)
hd2 = HandDraw(lines=lc3)
pz = PanZoom(scales={'x': [dt_x], 'y': [lc2_y]})

deb = Label(color='Black', font_size='24px')
deb.value = "hello"

In [ ]:
## Call back handler for the interactions
def test_callback(change):
    deb.value = str(change['new'])
    
multi_sel.observe(test_callback, names=['selected'])
br_intsel.observe(test_callback, names=['selected'])
index_sel.observe(test_callback, names=['selected'])
int_sel.observe(test_callback, names=['selected'])

In [ ]:
from collections import OrderedDict
selection_interacts = ToggleButtons(options=OrderedDict([('HandDraw1', hd), ('HandDraw2', hd2), ('PanZoom', pz), 
                                                       ('FastIntervalSelector', int_sel), ('IndexSelector', index_sel),
                                                       ('BrushIntervalSelector', br_intsel), ('MultiSelector', multi_sel),
                                                       ('None', None)]))
display(deb)
display(VBox([fig, selection_interacts], align_self="stretch"))

link((selection_interacts, 'value'), (fig, 'interaction'));

In [ ]:
# Set the scales of lc4 to the ones of lc2 and check if panzoom pans the two.
lc4.scales = lc2.scales